#ifndef _QUAD_TREE_NODE_
#define _QUAD_TREE_NODE_

#include "FEngineType.h"
#include "QuadTreeManager.h"
#include "AABB.h"
#include <list>

namespace FEngine
{

	/**
	 * Represent one node of a quad tree.
	 */
	class QuadTreeNode
	{

		public:

			/**
			 * Constructor.
			 * @param _float Minimum size of the node.
			 */
			QuadTreeNode(float _size);
			QuadTreeNode(const Vector3& _minPoint, float _size, int _inversedDeep, QuadTreeNode* _parentNode);
			QuadTreeNode* _initialize(float _size);
			QuadTreeNode* _initialize(const Vector3& _minPoint, float _size, int _inversedDeep, QuadTreeNode* _parentNode);
			~QuadTreeNode();

			/**
			 * Add an object to the tree.
			 * Traverse the children nodes until it found the correct node and return it.
			 * If needed the children nodes are created until we hit the 0 inversed deep of the tree.
			 * @param _pos Position contained in the node we are looking for.
			 * @param _nodeToCreate If the node does not exist, add this one instead. This node is deleted if needed, dont use it.
			 * @return The node that contains the given position or NULL if the node is outside the limits.
			 */
			QuadTreeNode* addObject(const Vector2& _pos, QuadTreeNode* _nodeToCreate);

			/**
			 * Return the center position of the node.
			 * @return Center position of the node.
			 */
			Vector3 getCenterPosition() const;

			/**
			 * Return the AABB of the node.
			 * @return The AABB of the node.
			 */
			AABB* getAABB() const;

			/**
			 * Return the size of the node.
			 * @return Size of the node.
			 */
			float getSize() const;

			/**
			 * Return the inversed deep of the node.
			 * @return Inversed deep of the node.
			 */
			int getInversedDeep() const;
			
			/**
			 * Check if the node is visible.
			 * This does not check the state of the visibility.
			 * It just send the last result of _computeFrustumCulling()
			 * @return The value of the visibility.
			 */
			NodeVisibility isVisible() const;

			/**
			 * Return the parent node of this node.
			 * @return The parent node.
			 */
			QuadTreeNode* getParentNode() const;

			/**
			 * Return a list of the four child nodes.
			 * @return List of the children.
			 */
			std::list<QuadTreeNode*> getChildren() const;
			
			/**
			 * Check the position of the given position inside the node.
			 * @param _pos Position to check.
			 * @return Relative position of the given position.
			 */
			QuadTreeManager::SquarePosition isPositionInLimit(const Vector2& _pos);

			
			void _addChildNode(QuadTreeNode* _childNode);
			void _setParentNode(QuadTreeNode* _parentNode);
			
			/**
			 * Check the visibility of the node and every children.
			 * @param _listVisibleNodes Pointer to the list containing the visible nodes.
			 * @param _maxView Cut the visibility to the given value.
			 * @return The number of visible node finals nodes (inversed deep = 0)
			 */
			int _computeFrustumCulling(std::list<QuadTreeNode*>* _listVisibleNodes, float _maxView);

			void _addToListIfFinal(std::list<QuadTreeNode*>* _listNodes);
			

		protected:
			
			AABB*			mAABB;
			float			mSize;
			NodeVisibility	mVisibility;


		private:

			int				mInversedDeep;

			QuadTreeNode*	mParentNode;
			QuadTreeNode*	mChildNode[4];

			Vector3 _getChildPosition(QuadTreeManager::SquarePosition _pos);
			
			/**
			 * Apply the given visibility to the node and its children.
			 */
			int _forceVisibility(NodeVisibility _visibility, std::list<QuadTreeNode*>* _listVisibleNodes);
};

} // namespace FEngine

#endif
